package main;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.*;


/**
 * @author dengqingchang
 */
public class OldCodeGenerator {

    public static void main(String[] args) {
        // 生成配置项开始 >>>
        // 代码生成人
        String author = "dengqingchang";
        // data source config
        //String url = "jdbc:mysql://192.168.56.211:3307/training?allowMultiQueries=true&useSSL=false";
        //String driver = "com.mysql.cj.jdbc.Driver";
        //String username = "intern";
        //String password = "intern";

        String driver = "oracle.jdbc.OracleDriver";
        String url = "jdbc:oracle:thin:@10.10.16.152:1521:XE";
        String username = "system";
        String password = "oracle";

        // 是否选择跳过服务对象的生成(注意: 如果不跳过, 且文件已存在会直接覆盖)
        boolean skipService = false;
        // 是否选择跳过Mapper Interface 对象生成 (注意: 如果不跳过, 且文件已存在会直接覆盖)
        boolean skipMapper = false;
        // 是否选择跳过Mapper Xml 文件生成 (注意: 如果不跳过, 且文件已存在会直接覆盖)
        boolean skipMapperXml = false;
        // 本次处理的表
        String[] handleTableNames = {"fas_property"};
        // 生成配置项结束 >>>


        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        //*************指定数据库表 *************
        // 控制台输入写法
        //strategy.setInclude(scanner("表名，多个英文逗号分割").split(","));
        // 包含的表名固定写法
        String[] tables = {
                "UITOOL_LIST_DISPLAY_FIELD",
                "UITOOL_FUNC_DISPLAY_INFO"
                //"deng_membership_info",
                //"deng_membership_card_info",
                //"deng_membership_level",
                //"deng_membership_logout",
                //"deng_good_info"
        };

        // 1.全局配置 **************************************************************************
        GlobalConfig gc = new GlobalConfig();
        //当前项目目录：如：D:\aa_train\mybaits-plus-generator-project
        String moduleName = "generator-old";
        String projectPath = System.getProperty("user.dir")+"/"+moduleName;
        //输出目录：如：D:\aa_train\mybaits-plus-generator-project/src/main/java
        gc.setOutputDir(projectPath + "/src/main/java");
        //作者
        gc.setAuthor(author);
        // 不打开输出目录
        gc.setOpen(false);
        // xml开启BaseResultMap
        gc.setBaseResultMap(true);
        // xml BaseColumnList
        gc.setBaseColumnList(true);
        // 日期格式  1.默认：DateType.TIME_PACK：LocalDateTime 2.DateType.ONLY_DATE:Date 3.DateType.SQL_PACK:Timestamp
        gc.setDateType(DateType.ONLY_DATE);
        // 是否覆盖已有文件，用于修改数据库后，重新生成
        gc.setFileOverride(true);
        // 开启 swagger2 模式
        //gc.setSwagger2(true);

        //名字指定:如I%sService 得到如IUserService，%s为对应User的的占位符号 ,null取默认
        gc.setEntityName(null);
        gc.setMapperName(null);
        gc.setXmlName(null);
        gc.setServiceName("I%sService");
        gc.setServiceImplName(null);
        gc.setControllerName(null);
        // ?(各种类型含义)实体类中指定生成的主键的ID类型
        gc.setIdType(IdType.AUTO);
        // ?(Kotlin)开启 Kotlin 模式
        gc.setKotlin(false);
        // 是否在xml中添加二级缓存配置
        gc.setEnableCache(false);

        mpg.setGlobalConfig(gc);

        // 2.数据源配置 **************************************************************************
        DataSourceConfig dsc = new DataSourceConfig();
        // 192.168.56.211:3307/training
        dsc.setUrl(url);
        // dsc.setSchemaName("public");
        dsc.setDriverName(driver);
        dsc.setUsername(username);
        dsc.setPassword(password);
        mpg.setDataSource(dsc);

        // 3.包配置 ********************************************************************************
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.focuschina")
                //.setModuleName("module01") 若设置模块则以下pojo,mapper...controller 在parent/module/下
                .setEntity("pojo")
                .setMapper("mapper")
                // xml 存储在下面自定义的 src/main/resources/mapper/下，不在这里
                .setService("service")
                .setServiceImpl("service.impl")
                .setController("controller");
        mpg.setPackageInfo(pc);

        // 4.自定义配置 *************************************************************************
        // 4.1.？（具体调用）自定义参数
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("data1","1.0.0");
                //map可以传递到模板引擎通过 cfg.xxx 引用
                this.setMap(map);
                // 这里防止父类已有的属性,在子类被生成
                this.setMap(Collections.singletonMap("superColumns", this.getConfig().getStrategyConfig().getSuperEntityColumns()));
            }
        };

        // 4.2. 可以定义xml的输出位置
        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 4.3 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出 templatePath对应模板引擎， 返回值确定输出位置
        if(!skipMapperXml){
            focList.add(new FileOutConfig(templatePath) {
                @Override
                public String outputFile(TableInfo tableInfo) {
                    // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                    // 这里配置：xml的自定义位置在：项目/src/main/resources/mapper/模块/实体名Mapper.xml
                    return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                            + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                }
            });
        }

        cfg.setFileOutConfigList(focList);
        // 4.4，自定义判断是否创建文件
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录，自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper 文件判断存在，不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });
        */
        mpg.setCfg(cfg);

        // 5.配置模板 *************************************************************************
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板 需要研究如何定制
        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
//         templateConfig.setEntity("templates/entity2.java");
//         templateConfig.setService("templates/service2.java");
//         templateConfig.setController("templates/controller2.java");
//         templateConfig.setServiceImpl("templates/serviceImpl2.java");
//         templateConfig.setMapper("templates/mapper2.java");
//
//         templateConfig.setXml(null);
//        mpg.setTemplate(templateConfig);
        templateConfig.setController(null);
        if (skipService) {
            templateConfig.setService(null);
            templateConfig.setServiceImpl(null);
        }
        if (skipMapper) {
            templateConfig.setMapper(null);
        }
        // 不在 Parent/mapper/xml下生成xml
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 6.策略配置(数据库表配置)  *************************************************************************
        StrategyConfig strategy = new StrategyConfig();

        //*************(1) entity *************
        // 6.1 数据库表名和javaDO实体名的对应设置
        // 6.1.1 表前缀:设置后，java的DO实体名不带前缀
        strategy.setTablePrefix("deng_");

        // 6.1.2 数据库表映射到实体的命名策略
        // no_change:membership_info-> Membership_info   不变 (默认)
        // underline_to_camel:membership_info -> MembershipInfo 下划线转驼峰
        strategy.setNaming(NamingStrategy.underline_to_camel);

        // 6.2 数据库字段名和javaDO实体属性名的对应设置
        // 6.2.1 字段前缀:设置后，java的DO实体属性名不带前缀，没有此前缀的字段不变。 具体字段和属性的对应在xml的resultMap进行映射
        //strategy.setFieldPrefix("membership_");
        // 6.2.2 数据库表字段映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        //Boolean类型字段是否移除is前缀（默认 false）
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);
        // 是否生成实体时，生成字段注解
        strategy.setEntityTableFieldAnnotationEnable(true);
        // 逻辑删除属性名称(效果：增加@TableLogic，当delete_flag为自己编写的公共实体父类，需要自己加@TableLogic在父类,因为mp管理不到自定义的父类)
        strategy.setLogicDeleteFieldName("delete_flag");

        // 自定义继承的Entity类全称，带包名 你自己的父类实体（需要的就自己写好）,没有就不用设置!（效果：实体类加上 extends 父类）
        //strategy.setSuperEntityClass(BaseEntity.class.getName());
        // 设置父类实体拥有的字段,自己不再拥有。如果不设置，实体自己仍产生与父类相同的字段。（效果：自己不产生这些字段，如果指定了SuperEntityClass，则通过继承得到，并且@EqualsAndHashCode(callSuper = true)）
        strategy.setSuperEntityColumns("delete_flag", "add_time", "update_time");

        // 是否为lombok模型（默认 false）: 有@Data @EqualsAndHashCode(callSuper = false)
        strategy.setEntityLombokModel(true);
        // 指定乐观锁属性名称
        //strategy.setVersionFieldName("version");
        // 表填充字段：使用，如add_time，在插入时自动填充当前时间(效果:对应字段添加@TableField 的fill值：如：@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE))
        // 适用与改字段不在自定义实体父类的场景，如果在父类，就自己在父类写@TableField，fill,因为生成器管理不到自己定义的父类。
        //List<TableFill> tableFillList = new ArrayList<>();
        //tableFillList.add(new TableFill("add_time", FieldFill.INSERT));
        //tableFillList.add(new TableFill("update_time", FieldFill.INSERT_UPDATE));
        //strategy.setTableFillList(tableFillList);



        //*************(2) mapper *************
        //自定义继承的Mapper类全称，带包名
        //strategy.setSuperMapperClass("");

        //*************(3) service *************
        // 自定义继承的Service类 serviceImpl类全称，带包名
        //strategy.setSuperServiceClass("");
        //strategy.setSuperServiceImplClass("");

        //*************(4) controller *************
        //生成@RestController控制器
        strategy.setRestControllerStyle(true);
        //自定义继承的Controller类全称，带包名
        strategy.setSuperControllerClass("");
        // ControllerMapping值驼峰转连字符:true:如：@RequestMapping("/membership-info)
        // false:如@RequestMapping("/membershipInfo")
        strategy.setControllerMappingHyphenStyle(true);

        strategy.setInclude(tables);
        mpg.setStrategy(strategy);

        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
    /**
     * <p>
     * 读取控制台内容
     * 配置参照：https://www.mybatis-plus.com/config/generator-config.html#open
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + "：");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "！");
    }
}
